// Package collector provides functionality for collecting metrics from libvirt
package collector

import (
	"time"

	"libvirt.org/go/libvirt"
)

// DomainInfoMetrics represents the basic domain runtime information
type DomainInfoMetrics struct {
	Name          string    // domain name
	UUID          string    // domain uuid
	Status        float64   // domain state (running, paused, etc.)
	StateReason   string    // optional: state reason description
	CPUTime       float64   // accumulated CPU time in seconds
	Uptime        float64   // uptime in seconds
	HasUptime     bool      // whether uptime is available
	MemoryCurrent float64   // current memory usage in bytes
	MemoryMax     float64   // maximum configured memory in bytes
	Autostart     bool      // domain autostart flag
	Persistent    bool      // whether domain is persistent
	ManagedSave   bool      // managed save image exists
	BootTime      time.Time // guest boot time
}

// CPUStatsMetrics represents vCPU and scheduling metrics
type CPUStatsMetrics struct {
	Name         string // domain name
	UUID         string // domain uuid
	VCPUsMax     uint   // maximum vCPU count
	VCPUsCurrent uint   // current active vCPUs
	CPUTime      uint64 // total CPU time in nanoseconds
	UserTime     uint64 // guest user time in nanoseconds
	SystemTime   uint64 // guest system time in nanoseconds
	StealTime    uint64 // vCPU steal time in nanoseconds
	Scheduler    string // scheduler type (e.g. "cfs", "rt")
	Quota        int64  // CPU quota in microseconds
	Period       int64  // CPU period in microseconds
	Affinity     string // CPU affinity bitmap string
}

// MemoryStatsMetrics represents guest memory balloon and usage metrics
type MemoryStatsMetrics struct {
	Name        string           // domain name
	UUID        string           // domain uuid
	BalloonSize uint64           // current balloon size in KB
	Unused      uint64           // guest unused memory in KB
	Available   uint64           // guest available memory in KB
	RSS         uint64           // resident set size in KB
	SwapIn      uint64           // swap in in KB
	SwapOut     uint64           // swap out in KB
	MajorFaults uint64           // major page faults
	MinorFaults uint64           // minor page faults
	Total       uint64           // total assigned memory in KB
	NUMANodes   []NUMANodeMemory // per-node memory statistics
}

// NUMANodeMemory represents per-node memory statistics
type NUMANodeMemory struct {
	NodeID  int    // NUMA node identifier
	UsedKB  uint64 // used memory in KB
	TotalKB uint64 // total memory in KB
	FreeKB  uint64 // free memory in KB
}

// DiskMetrics represents raw disk I/O and capacity metrics
type DiskMetrics struct {
	Name        string           // domain name
	UUID        string           // domain uuid
	Device      string           // device name (e.g. "vda")
	Path        string           // device path
	ReadBytes   int64            // bytes read
	WriteBytes  int64            // bytes written
	ReadOps     int64            // read operations
	WriteOps    int64            // write operations
	ReadTimeNs  int64            // time spent reading in nanoseconds
	WriteTimeNs int64            // time spent writing in nanoseconds
	FlushOps    int64            // flush operations
	FlushBytes  int64            // bytes flushed
	Capacity    int64            // total virtual disk size
	Allocation  int64            // allocated bytes on host
	Physical    int64            // physical bytes consumed on storage
	CacheMode   string           // cache mode (e.g. "none", "writethrough")
	BlockJob    *BlockJobMetrics // active block job metrics (if any)
}

// BlockJobMetrics represents active disk job (e.g. commit, copy, mirror)
type BlockJobMetrics struct {
	Type      string  // job type: "copy", "commit", "active-commit", etc.
	Progress  float64 // job progress from 0.0 to 1.0
	Bandwidth uint64  // bandwidth limit in bytes per second
}

// NetworkMetrics represents network interface statistics
type NetworkMetrics struct {
	Name        string // domain name
	UUID        string // domain uuid
	Interface   string // interface name (e.g. "vnet0")
	MACAddress  string // MAC address
	Type        string // interface type: bridge, macvtap, vhostuser, etc.
	RxBytes     int64  // received bytes
	TxBytes     int64  // transmitted bytes
	RxPackets   int64  // received packets
	TxPackets   int64  // transmitted packets
	RxErrors    int64  // receive errors
	TxErrors    int64  // transmit errors
	RxDrops     int64  // receive drops
	TxDrops     int64  // transmit drops
	BandwidthRx int64  // receive bandwidth limit in bps
	BandwidthTx int64  // transmit bandwidth limit in bps
	Multiqueue  bool   // whether multiqueue is enabled
}

// DeviceMetrics represents virtual devices attached to the domain
type DeviceMetrics struct {
	Name        string       // domain name
	UUID        string       // domain uuid
	HasTPM      bool         // whether TPM device is present
	HasRNG      bool         // whether RNG device is present
	PCIDevices  []PCIDevice  // PCI passthrough devices
	USBDevices  []USBDevice  // USB passthrough devices
	VGPUDevices []VGPUDevice // mediated devices (vGPUs)
	Snapshots   int          // number of snapshots
}

// PCIDevice represents a PCI passthrough device
type PCIDevice struct {
	Address string // PCI address (e.g. "0000:00:02.0")
	Type    string // device type (e.g. "GPU", "NIC")
	Driver  string // driver in use (e.g. "vfio-pci")
}

// USBDevice represents a USB passthrough device
type USBDevice struct {
	Bus     int    // USB bus number
	Device  int    // USB device number
	Product string // product name
	Vendor  string // vendor name
}

// VGPUDevice represents mediated device (vGPU)
type VGPUDevice struct {
	MdevUUID string // mediated device UUID
	Model    string // device model (e.g. "nvidia-222")
}

// DomainJobMetrics represents job progress (e.g. migration, block copy)
type DomainJobMetrics struct {
	Name        string  // domain name
	UUID        string  // domain uuid
	Type        string  // job type: "migration", "block-commit", etc.
	Progress    float64 // job progress from 0.0 to 1.0
	Remaining   uint64  // bytes remaining
	Transferred uint64  // bytes transferred
	Total       uint64  // total bytes
	SpeedBps    uint64  // current transfer speed in bytes per second
}

// SnapshotMetrics represents snapshot statistics
type SnapshotMetrics struct {
	Name       string    // domain name
	UUID       string    // domain uuid
	Count      int       // total snapshot count
	LastCreate time.Time // last snapshot creation time
	LastDelete time.Time // last snapshot deletion time
}

// ConnectionMetrics represents libvirt connection and host statistics
type ConnectionMetrics struct {
	// Basic connection info
	URI               string            // connection URI
	Hostname          string            // host hostname
	DriverType        string            // driver type
	IsAlive           bool              // whether connection is alive
	LibvirtVersion    uint64            // libvirt version
	HypervisorVersion uint64            // hypervisor version
	NodeInfo          *libvirt.NodeInfo // node information
	FreeMemory        uint64            // free memory in bytes

	// Host resource info
	ActiveDomains       int                    // count of active domains
	DefinedDomains      int                    // count of defined domains
	FreeMemoryBytes     uint64                 // free memory in bytes
	TotalMemoryBytes    uint64                 // total memory in bytes
	TotalCPUs           uint                   // total CPU count
	HostCPUUsagePercent float64                // host CPU usage percentage
	StoragePools        []StoragePoolMetrics   // storage pool metrics
	Networks            []NetworkPoolMetrics   // virtual network metrics
	Interfaces          []HostInterfaceMetrics // host interface metrics
}

// StoragePoolMetrics represents storage pool stats
type StoragePoolMetrics struct {
	Name       string // pool name
	Type       string // pool type
	State      string // pool state
	Capacity   uint64 // pool capacity in bytes
	Allocation uint64 // allocated space in bytes
	Available  uint64 // available space in bytes
	Volumes    int    // volume count
}

// NetworkPoolMetrics represents virtual network stats
type NetworkPoolMetrics struct {
	Name   string // network name
	Active bool   // whether network is active
	Bridge string // bridge interface name
}

// HostInterfaceMetrics represents physical NIC stats on host
type HostInterfaceMetrics struct {
	Name      string // interface name
	RxBytes   uint64 // received bytes
	TxBytes   uint64 // transmitted bytes
	RxPackets uint64 // received packets
	TxPackets uint64 // transmitted packets
}

// ExporterMetrics represents exporter self-monitoring metrics
type ExporterMetrics struct {
	Up                bool      // exporter connected to libvirt successfully
	LastScrapeTime    time.Time // last successful scrape time
	ScrapeDurationSec float64   // time taken for last scrape in seconds
	ScrapeErrorsTotal uint64    // total scrape errors
	DomainsDiscovered int       // number of domains discovered
	CacheHits         uint64    // cache hits count
	CacheMisses       uint64    // cache misses count
	BuildVersion      string    // build version
	BuildCommit       string    // build commit hash
}

// MetricsCollector defines interface for collecting raw metrics from libvirt
// Each method corresponds to a specific type of metrics
type MetricsCollector interface {
	// CollectDomainInfo collects basic domain information
	CollectDomainInfo(
		conn *libvirt.Connect,
		domain *libvirt.Domain,
	) (*DomainInfoMetrics, error)

	// CollectCPUStats collects CPU and vCPU statistics
	CollectCPUStats(
		conn *libvirt.Connect,
		domain *libvirt.Domain,
	) (*CPUStatsMetrics, error)

	// CollectMemoryStats collects memory statistics
	CollectMemoryStats(
		conn *libvirt.Connect,
		domain *libvirt.Domain,
	) (*MemoryStatsMetrics, error)

	// CollectDiskStats collects disk I/O statistics
	CollectDiskStats(
		conn *libvirt.Connect,
		domain *libvirt.Domain,
	) ([]DiskMetrics, error)

	// CollectNetworkStats collects network I/O statistics
	CollectNetworkStats(
		conn *libvirt.Connect,
		domain *libvirt.Domain,
	) ([]NetworkMetrics, error)

	// CollectDeviceStats collects device information
	CollectDeviceStats(
		conn *libvirt.Connect,
		domain *libvirt.Domain,
	) (*DeviceMetrics, error)

	// CollectJobStats collects active job statistics
	CollectJobStats(
		conn *libvirt.Connect,
		domain *libvirt.Domain,
	) (*DomainJobMetrics, error)

	// CollectSnapshotStats collects snapshot statistics
	CollectSnapshotStats(
		conn *libvirt.Connect,
		domain *libvirt.Domain,
	) (*SnapshotMetrics, error)

	// CollectConnectionStats collects libvirt connection and host statistics
	CollectConnectionStats(
		conn *libvirt.Connect,
	) (*ConnectionMetrics, error)
}

// DomainMetrics aggregates all metrics for one domain
type DomainMetrics struct {
	Info     DomainInfoMetrics  // basic domain information
	CPU      CPUStatsMetrics    // CPU statistics
	Memory   MemoryStatsMetrics // memory statistics
	Disks    []DiskMetrics      // disk I/O statistics
	Networks []NetworkMetrics   // network I/O statistics
	Devices  DeviceMetrics      // device information
	Job      *DomainJobMetrics  // active job information (if any)
	Snapshot SnapshotMetrics    // snapshot statistics
}
